#include "bsp_bc26.h"
#include "tools.h"
#include "msg.h"
#include "bsp_led.h"

BC26_STRUCTURE_T bc26;


/*
需要有系统运行时间支持，sys_ms
*/



/***********************************************************************************************************
函数名称 ： BC26_CheckCmd
功    能 ： 检测子字符串是否存在
参    数 ： str   - 需要查找的子字符串
返 回 值 ： 1->找到     -1->未找到
作    者 ： FlySnail
***********************************************************************************************************/
int8_t BC26_CheckCmd(char *str,int len,uint32_t waittime)
{
	int res=-1;
	uint64_t send_time = sys_ms;
	while(1)
	{
		res = checkStr((char *)bc26.buff, str, bc26.index, len);
		if(res!=-1)
		{
			return 1;
		}
		if(send_time+waittime < sys_ms)  
		{
			return -1;
		}
	}
}



/***********************************************************************************************************
函数名称 ： BC26_CheckCmd
功    能 ： 发送命令，同步检测命令返回值
参    数 ： cmd   - 需要发送的命令（字符串）
						ack   — 需要检测的返回命令（字符串）
						len   - 需要检测的返回命令长度
						waittime  - 等待时间
返 回 值 ： 1->成功     -1->失败
作    者 ： FlySnail
***********************************************************************************************************/
int8_t BC26_SendCmd(char *cmd,char *ack,int len,uint32_t waittime)
{
	int8_t res=0;
	bc26.index = 0;
	memset(bc26.buff, 0, BC26_DATA_LEN);    	//清空接收区
	bc26.state = STARTB;
	BC26_Puts(cmd);
	bc26.state = BUSYB;
	res = BC26_CheckCmd(ack,len, waittime);
	if(res==1)		bc26.state = IDELB;
	else 					bc26.state = TIMEOUTB;
	return res;
}


 

/***********************************************************************************************************
函数名称 ： BC26_Init
功    能 ： 初始化BC26硬件端口和设备状态
参    数 ： 无
返 回 值 ： 无
作    者 ： FlySnail
***********************************************************************************************************/
void BC26_Init(void)
{
	int8_t stat=0;
	int8_t count=0; // 累计获取IP地址次数，如果长时间没有获取到就表示入网失败
	// 端口初始化
	GPIO_InitTypeDef  GPIO_InitStructure;
	//参数初始化
	bc26.state = INITB;
	
	BC26_USART_Init();
	
  RCC_APB2PeriphClockCmd(BC26_EINT_RCC | BC26_REST_RCC| BC26_KEY_RCC, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = BC26_EINT_PIN;              
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;           
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  GPIO_Init(BC26_EINT_PORT, &GPIO_InitStructure); 
	   
	GPIO_InitStructure.GPIO_Pin = BC26_REST_PIN;              
  GPIO_Init(BC26_REST_PORT, &GPIO_InitStructure); 
	
	GPIO_InitStructure.GPIO_Pin = BC26_KEY_PIN;              
  GPIO_Init(BC26_KEY_PORT, &GPIO_InitStructure); 
	
	
	// 开机----------------
	BC26_REST_H;	
	BC26_delay_us(500000);
	BC26_REST_L;	
	BC26_delay_us(500000); 
	// ------------------
	
	// 可以不要----------
	BC26_BOOT_L;
	BC26_EINT_H;
	BC26_delay_ms(20);
	BC26_EINT_L;
	// ------------------
	bc26.state = IDELB;
	bc26.isWait = NO;
	
	memset(bc26.imei,0,sizeof(bc26.imei));
	memset(bc26.serverIp,0,sizeof(bc26.serverIp));
	
	
	
	BC26_BaudSynchronization();   // 同步波特率
	if(BC26_CloseDormancyCMD()!=SUCCESS) 			// 禁用休眠
	{
		// 设备连接错误
		bc26.initStat = HARDWARE_ERR;
		return;
	}
	
	
	if(BC26_GetIMEI()!=SUCCESS) 			// 获取IMEI卡号
	{
		// 卡号获取失败，卡没有插好
		bc26.initStat = IMEI_ERR;
		return;
	}
	
	
	// 等待获取IP,IP必须获取成功才能连接网络
	while(1)
	{
		BC26_delay_ms(2000);
		int8_t temp = BC26_GetIPCMD(); // 获取IP地址
		if(strlen(bc26.ip)>3)  break;
		count++;
		if(count>30) // 2*30=60秒，1分钟没有获取到IP地址说明联网失败
		{
			// 网络异常
			bc26.initStat = IP_ERR;
			return;
		}
	}
	
	if(BC26_GetInNetStateCMD()!=SUCCESS) 			// 查询网络注册状态
	{
		// 入网失败，信号不好
		bc26.initStat = INNET_ERR;
		return;
	}
	
	
	if(BC26_GetQENGCMD()!=SUCCESS) 			// 信号强度查询
	{
		// 入网失败，信号不好
		bc26.initStat = INNET_ERR;
		return;
	}
	
	
	
	if(BC26_SetDataHexCMD()!=SUCCESS) 			// 设置数据传输格式为16进制
	{
		// 格式传输设置失败
		bc26.initStat = HEX_CMD_ERR;
		return;
	}
	
	bc26.initStat = INIT_SUCCESS;
}

		
		

/***********************************************************************************************************
函数名称 ： BC26_UploadDataWithoutRes
功    能 ： 上传数据,不需要解析返回值
参    数 ： data  -  需要发送的数组
						len   -  数组长度
返 回 值 ： 1  -> 发送成功
						0 -> 发送失败(网络或者IP有问题)
作    者 ： FlySnail     
***********************************************************************************************************/
int8_t BC26_UploadDataWithoutRes(uint8_t *data,uint8_t len)
{
	bc26.isWait = NO;
	//if(strlen(bc26.serverIp)<5) return ERROR;  // 检测IP地址有没有问题

	if(BC26_ConnectCMD(bc26.serverIp, bc26.serverPort)==SUCCESS) 			// 网络连接
	//if(BC26_ConnectCMD("112.74.89.58", 32808)==SUCCESS) 			// 网络连接
	{
		BC26_SendData(data, len);
		BC26_DisconnectCMD();
		return SUCCESS;
	}
	return ERROR;
}


/***********************************************************************************************************
函数名称 ： BC26_BaudSynchronization
功    能 ： 波特率同步
参    数 ： 无
返 回 值 ： 无
作    者 ： FlySnail
***********************************************************************************************************/
void BC26_BaudSynchronization(void)
{
	// 3次AT指令同步波特率，默认9600
	for(uint8_t i=0;i<3;i++)
	{
		BC26_SendCmd("AT\r\n","OK\r\n",4,1000);     
	}
	bc26.index = 0;			
}

/***********************************************************************************************************
函数名称 ： BC26_SetDataHexCMD
功    能 ： 设置数据传输方式为16进制
参    数 ： 无
返 回 值 ： 1->成功     -1->失败
作    者 ： FlySnail
***********************************************************************************************************/
int8_t BC26_SetDataHexCMD(void)
{
	int8_t sta = BC26_SendCmd("AT+QICFG=\"dataformat\",1,1\r\n","OK\r\n",4,1000);    // 不管有没有连接，先关闭
	BC26_delay_ms(200);
	return sta;
}




/***********************************************************************************************************
函数名称 ： BC26_GetQENGCMD
功    能 ： 获取信号强度，一般通过RSRP和SNR（信噪比）值来综合判断
						1. RSRP>-100dBm 且 SNR>-3dB : 信号比较稳定，成功率高
						2. -110dBm<RSRP<-100dBm 且 -3dB<SNR<-3dB : 信号相对较差
						3. RSRP<-115dBm 且 SNR<-3dB : 信号差，基本不能正常使用
	AT+QENG=0

	+QENG: 0,3689,11,347,"0569C847",-86,-7,-81,12,8,"2B03",0,14,3

	OK


参    数 ： 无
返 回 值 ： 1->成功     0->失败
作    者 ： FlySnail
***********************************************************************************************************/
int8_t BC26_GetQENGCMD(void)
{
	int8_t flag=0;
	int8_t sta = BC26_SendCmd("AT+QENG=0\r\n","OK\r\n",4,1000);   
	BC26_delay_ms(200);
	if(sta==SUCCESS)
	{
		for(int i=0;i<bc26.index;i++)
		{
			if(bc26.buff[i]== ':' && flag==0)
			{
					flag = 1;
			}				
			else if(bc26.buff[i]==',' && flag)			// 数,号
			{
				flag++;
			}
			
			if(flag == 1)  
			{
				
			}
			else if(flag == 2)  
			{
				
			}
			else if(flag == 3)  
			{
				
			}
			else if(flag == 4)  
			{
				
			}
			else if(flag == 5)  
			{
				
			}
			else if(flag == 6)  
			{
				
			}
			else if(flag == 7)  
			{
				
			}
			else if(flag == 8)  
			{
				
			}
			else if(flag == 9)  
			{
				
			}
			else if(flag == 10)  
			{
				
			}
			else if(flag == 11)  
			{
				
			}
			else if(flag == 12)  
			{
				
			}
			else if(flag == 13)  
			{
				
			}
			else if(flag == 14)  
			{
				
			}
		}
		return SUCCESS;
	}
	return ERROR;
}




/***********************************************************************************************************
函数名称 ： BC26_DisconnectCMD
功    能 ： 断开网络连接，发送完后立即断开
参    数 ： 无
返 回 值 ： 1->成功     -1->失败
作    者 ： FlySnail
***********************************************************************************************************/
int8_t BC26_DisconnectCMD(void)
{
	int8_t sta = BC26_SendCmd("AT+QICLOSE=0\r\n","OK\r\n",4,1000);    // 不管有没有连接，先关闭
	BC26_delay_ms(200);
	return sta;
}


/***********************************************************************************************************
函数名称 ： BC26_CloseDormancyCMD
功    能 ： 禁用休眠命令
参    数 ： 无
返 回 值 ： 1->成功     -1->失败
作    者 ： FlySnail
***********************************************************************************************************/
int8_t BC26_CloseDormancyCMD(void)
{
	int8_t sta = 	BC26_SendCmd("AT+QSCLK=0\r\n","OK\r\n",4,1000);      // 禁用休眠
	BC26_delay_ms(100);
	return sta;
}


/***********************************************************************************************************
函数名称 ： BC26_GetInNetStateCMD
功    能 ： 查询网络注册状态
参    数 ： 无
返 回 值 ： 1->成功     -1->失败
作    者 ： FlySnail
***********************************************************************************************************/
int8_t BC26_GetInNetStateCMD(void)
{
	int8_t sta = BC26_SendCmd("AT+CEREG?\r\n","OK\r\n",4,1000);    // 查询网络注册状态
	BC26_delay_ms(100);
	return sta;
}
 
/***********************************************************************************************************
函数名称 ： BC26_ConnectCMD
功    能 ： 进行网络连接命令
参    数 ： ip 		-	 服务器ip地址，可以是域名（不含端口）
						port	-  服务器端口号

返 回 值 ： 1->成功     -1->失败
作    者 ： FlySnail
***********************************************************************************************************/
int8_t BC26_ConnectCMD(char *ip,uint32_t port)
{
	char p[100];
	sprintf((char *)p,(char *)("AT+QIOPEN=0,0,\"TCP\",\"%s\",%d\r\n"),ip, port);
	int8_t sta = BC26_SendCmd(p, "0,0\r\n",5,3000);
	return sta;
}


/***********************************************************************************************************
函数名称 ： BC26_GetIP
功    能 ： 获取IP地址
参    数 ： 无
返 回 值 ： 1:入网成功   0：入网失败
作    者 ： FlySnail
***********************************************************************************************************/
uint8_t BC26_GetIPCMD(void)
{
	int8_t sta = -1;
	memset(bc26.buff, 0, BC26_DATA_LEN);    	//清空接收区
	bc26.index = 0;
	sta = BC26_SendCmd("AT+CGPADDR?\r\n","OK\r\n",4,1000);  
	if(sta==1 && bc26.index>30)		// 超30字节说明包含IP地址
	{
		uint8_t flag=0, index=0;
		for(int i=0;i<bc26.index;i++)
		{
			if(bc26.buff[i]==0x2C)			// 找到开始标志  0x20是,号的码值
			{
				flag = 1;
				index = 0;
			}
			else if(flag)  
			{
				if(bc26.buff[i]==0x0D)   // 判断有没有记录完
				{
					break;
				}
				else
				{
					bc26.ip[index] = bc26.buff[i];
					index++;
				}
			}
		}
		bc26.index = 0;
		return 1;
	}
	return 0;
}



/***********************************************************************************************************
函数名称 ： BC26_GetNetStat
功    能 ： 通过获取IP地址判断是否入网成功
参    数 ： 无
返 回 值 ： 1：成功    0：失败
作    者 ： FlySnail
***********************************************************************************************************/
uint8_t BC26_GetNetStat(uint32_t waittime)
{
	int res=0;
	uint64_t send_time = sys_ms;
	while(1)
	{
		memset(bc26.buff, 0, BC26_DATA_LEN);    	//清空接收区
		bc26.index = 0;
		BC26_Puts("AT+CGATT?\r\n");
		BC26_delay_ms(500);
		res = checkStr((char *)bc26.buff, "1\r\n", bc26.index,3);
		if(res!=-1)  // 查询到了
		{
			return 1;
		}
		if(send_time+waittime < sys_ms) break;
	}
	return 0;
}




/***********************************************************************************************************
函数名称 ： BC26_GetIMEI
功    能 ： 检查IMEI号
参    数 ： 无
返 回 值 ： 1：成功    0：失败
作    者 ： FlySnail
***********************************************************************************************************/
uint8_t BC26_GetIMEI(void)
{
	int res=0;
	int8_t flag=-1,index;
	res = BC26_SendCmd("AT+CGSN=1\r\n","OK\r\n",4,500); 
	BC26_delay_ms(500);
	if(res==1)  // 有号码
	{
		for(int i=0;i<bc26.index;i++)
		{
			if(bc26.buff[i]== ':' && flag==-1)
			{
					flag = 0;
			}				
			else if(bc26.buff[i]>=0x30 && bc26.buff[i]<=0x39 && flag==0)			// 号码开始
			{
				flag = 1;
				index = 0;
			}
			if(flag == 1)  
			{
				if(bc26.buff[i]==0x0D)   // 判断有没有记录完
				{
					break;
				}
				else
				{
					bc26.imei[index] = bc26.buff[i];
					index++;
				}
			}
		}
		
		if(index!=17)  // 如果长度不足17位，在前面补0
		{
				for(int8_t i=index;i>=0;i--)
        {
            bc26.imei[i+(17-index)] = bc26.imei[i];  
            if(i<(17-index))    bc26.imei[i] = 0x30;    
        }
		}
		bc26.index = 0;
		return 1;
	}
	return 0;
}



/***********************************************************************************************************
函数名称 ： BC26_StatShow
功    能 ： 状态显示（LED提示）
参    数 ： stat  -  状态类型
返 回 值 ： 无
作    者 ： FlySnail
***********************************************************************************************************/
void BC26_StatShow(enum INIT_STAT stat)
{
		switch(stat)
		{
				case INNET_OK:   			ledStat= BREATH;break;
				case INNET_ERR:   		ledStat= FLICKER_F;break;
				case HARDWARE_ERR:   	ledStat= OFF;break;
				case IMEI_ERR:   			ledStat= OFF;break;
				case IP_ERR:   				ledStat= FLICKER_F;break;
				case HEX_CMD_ERR:   	ledStat= ON;break;
			dafault:break;
		}
}



/***********************************************************************************************************
函数名称 ： BC26_RecvHandle
功    能 ： 数据接收方法，放到对应串口中断
参    数 ： data  -  接收到的数据
返 回 值 ： 无
作    者 ： FlySnail
***********************************************************************************************************/
void BC26_RecvHandle(uint8_t data)
{
	bc26.buff[bc26.index] = data;
	bc26.index++;
	if(bc26.index>=BC26_DATA_LEN)			bc26.index = 0;
	if(bc26.isWait==YES)  // 有必要解析才处理
	{   
		BC26_Parse(data);
	}
}


/***********************************************************************************************************
函数名称 ： BC26_SendStr
功    能 ： 字符串发送
参    数 ： data  -  需要发送的字符串
						len   -  字符串长度
返 回 值 ： 0  -> 没联网
						1  -> 发送成功
						-1 -> 发送失败（消息拼接有问题）
作    者 ： FlySnail
***********************************************************************************************************/
int8_t BC26_SendStr(char *data,uint8_t len)
{
	int8_t sta = -1;
	char p[255]={0};	
	sprintf((char *)p,(char *)("AT+QISEND=0,%d,%s\r\n"),len,data);
	sta = BC26_SendCmd(p, " OK\r\n",4,2000);
	return sta;
}




/***********************************************************************************************************
函数名称 ： BC26_SendData
功    能 ： 16进制数组发送
参    数 ： data  -  需要发送的数组
						len   -  数组长度
返 回 值 ： 0  -> 没联网
						1  -> 发送成功
						-1 -> 发送失败（消息拼接有问题）
作    者 ： FlySnail
***********************************************************************************************************/
int8_t BC26_SendData(uint8_t *data,uint8_t len)   
{
	char dataTemp[255]={0};	  	
	int index=0;
	int8_t sta = -1;
	char p[255]={0};	
	for(int i=0;i<len;i++)
	{
		sprintf((char *)dataTemp+index,(char *)("%02x"),data[i]);
		index+=2;
	}

	sprintf((char *)p,(char *)("AT+QISEND=0,%d,\"%s\"\r\n"),len,dataTemp);
	sta = BC26_SendCmd(p, "OK\r\n",4,2000);  

	return sta;
}

/**************************************************** 
*检测服务器是否正常连接，通过调用数据接收是否正常
* 如果连接正常：
* AT+QIRD=0,1   (从0号连接上接收1个字节数据)
*
* +QIRD: 0
*
* OK
*
* 如果连接接断开：
* AT+QIRD=0,1
*
* ERROR
*****************************************************/
uint8_t BC26_NetStat(void)
{
	int8_t res=0;
	res = BC26_SendCmd("AT+QIRD=0,1\r\n","OK\r\n",4,500);
	if(res!=-1)		return ON_LINE;
	else 					return OUT_LINE;
}


/****************************************************
通过判断是否接受到+QIURC: "closed",0来判断是否断开
0:断开
1：未断开
*****************************************************/
uint8_t BC26_CheckStat(void)
{
	int res = checkStr((char *)bc26.buff, "\"closed\"", bc26.index, 8);
	if(res!=-1)  
	{
		return OUT_LINE;
	}
	else  			 
	{
		return ON_LINE;
	}
}



/*
解析具体BC26收到的数据内容
+QIURC: "recv",0,22,"26134f0029010203040102030406070809020406086e"

*/
char parseData[BC26_DATA_LEN]={0},reFlag=0;
uint16_t reIndex=0;  // 消息帧解析的缓存
uint16_t dataLenTemp=0; // 临时记录数据长度
uint8_t hexbuf[BC26_DATA_LEN/2];
uint16_t hexbufLen;
uint8_t BC26_Parse(uint8_t data)
{			
	parseData[reIndex] = data;
	reIndex++;

	if(myStrstr(parseData, "\"recv\",0,",reIndex,9)!=-1 && reFlag==0)    // 解析到消息头 
	{
			reFlag = 1; 
			dataLenTemp = 0;
	}
	if(reFlag==1)     // 收到消息头后开始解析消息长度信息
	{
			if(data!=',' && data!='"')    // 解析整个数据长度（按hex计算，字符数/2）   
			{
				dataLenTemp = dataLenTemp*10+(data-0x30);   // 字符转数字
			}
			if(data=='"')     // 包裹数据的第一个 "           
			{
					reIndex = 0;
					reFlag=2;
			}
	}
	else if(reFlag==2)  //  根据长度信息接收数据内容
	{
		if(dataLenTemp>0)  // 存在有用消息
		{
			if(dataLenTemp*2==reIndex)    // 16进制字符串 
			{
					reFlag=0;  //接收完成
				
					// 字符串转16进制数组
					str2hex((char *)parseData, &hexbufLen, hexbuf);
					
					// 解析具体协议内容
//					for(uint16_t i=0;i<hexbufLen;i++)
//					{
//							msgResult = msgParse(hexbuf[i], &msg);
//							if(msgResult==1) 
//							{
//								reIndex = 0;
//								reFlag=0;
//								memset(parseData,0,BC26_DATA_LEN);
//								return 1;
//							}
//					}
			}
		}
		else{ // 不存在有用消息
			reFlag=0;
		}
	}
	
// 防止溢出
	if(reIndex>=BC26_DATA_LEN){
		reIndex = 0;
		reFlag=0;
	}
	return 0;
}
//AT+QIRD=0,1

// BC26_SendStr("qwe123",6);
// uint8_t buf[8]={0x10,0x0E,0x00,0x20,0xCD,0xF0,0x00,0x08};
// BC26_SendData(buf,8);


